package org.jsola.hr.common.wechat;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.jsola.common.FileKit;
import org.jsola.exception.ParamException;
import org.jsola.hr.constant.ConfigCodeConstants;
import org.jsola.hr.provider.IFileProviderService;
import org.jsola.hr.provider.ISiteConfigProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 小程序二维码处理类
 */
@Slf4j
@Component
public class QRCodeUtils {

    @Autowired
    private ISiteConfigProviderService siteConfigProviderService;

    @Autowired
    private IFileProviderService fileProviderService;

    /**
     * 生成二维码path最大长度
     */
    private static final Integer PATH_MAX_LENGTH = 128;


    /**
     * 生成扫码待入职二维码
     *
     * @param params 参数
     * @param siteId 租户id
     * @return url
     */
    public String getQRCode(String params, String siteId) {
        // appid ,secret
        String appid = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_APPID, siteId);
        String secret = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_SECRET, siteId);
        String page = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_PAGE_QRCODE, siteId);
        return getQRCode(appid, secret, page, params);
    }

    /**
     * 生成发薪二维码
     *
     * @param params 参数
     * @param siteId 租户id
     * @return url
     */
    public String getSalaryQRCode(String params, String siteId) {
        // appid ,secret
        String appid = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_APPID, siteId);
        String secret = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_SECRET, siteId);
        String page = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_PAGE_SALARY, siteId);
        return getQRCode(appid, secret, page, params);
    }

    /**
     * 生成职薪人小程序二维码
     *
     * @param params 参数
     * @param siteId 租户id
     * @return url
     */
    public String getManageQRCode(String params, String siteId) {
        String appid = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_APPID, siteId);
        String secret = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_SECRET, siteId);
        String page = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MANAGE_MINI_PAGE, siteId);
        return getQRCode(appid, secret, page, params);
    }

    private String getQRCode(String appid, String secret, String page, String params) {
        log.info("appid:{},secret:{},page:{}", appid, secret, page);
        Map<String, Object> parameters = new HashMap<>(16);
        String accessToken = MessageHandlerUtil.getAccessToken(appid, secret).getAccessToken();
        parameters.put("width", 430);
        if (page.contains("?")) {
            parameters.put("path", page + "&" + params);
        } else {
            parameters.put("path", page + "?" + params);
        }
        // 这个接口有10w次的调用次数限制
        // 第三方文档：https://www.bookstack.cn/read/wechat-game-api/303.md
        String url = "https://api.weixin.qq.com/wxa/getwxacode?access_token=" + accessToken;
        // 最大长度128
        int length = parameters.get("path").toString().length();
        log.info("生成二维码path长度:{},parameters:{}", length, parameters.get("path"));
        if (length > PATH_MAX_LENGTH) {
            throw new ParamException("生成二维码path长度不能超过" + PATH_MAX_LENGTH + "，当前长度:" + length + "，请联系管理员处理");
        }
        byte[] bytes = HttpUtils.httpPostByte(url, parameters);
        File file;
        ByteArrayInputStream byteArrayInputStream;
        try {
            byteArrayInputStream = new ByteArrayInputStream(bytes);
            BufferedImage image = ImageIO.read(byteArrayInputStream);
            if (image == null) {
                String error = new String(bytes, StandardCharsets.UTF_8);
                log.error("获取二维码失败:{}", error);
                return null;
            }

            String systemTempPath = FileKit.getSystemTempPath();
            String fileName = "manageQRCode.png";
            new File(systemTempPath).mkdir();
            file = new File(systemTempPath, fileName);
            ImageIO.write(image, "jpg", file);

            byteArrayInputStream.close();
            FileItem fileItem = createFileItem(file);

            List<String> list =
                    fileProviderService.generalUpload(new CommonsMultipartFile(fileItem), "inline");
            if (CollectionUtils.isEmpty(list)) {
                return null;
            }
            log.info("生成二维码本地路径地址 :{}", file.getPath());
            log.info("生成二维码地址 :{}", list.get(0));
            byteArrayInputStream.close();
            // 删除临时文件
            file.delete();
            return list.get(0);
        } catch (IOException e) {
            log.error("生成小程序二维码失败:{}", e.getMessage());
        }
        return null;
    }

    /**
     * File 转 FileItem
     */
    private FileItem createFileItem(File file) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem("textField", "text/plain", true, file.getName());
        int bytesRead;
        byte[] buffer = new byte[8192];
        try {
            FileInputStream fis = new FileInputStream(file);
            OutputStream os = item.getOutputStream();
            while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return item;
    }


}
